package com.gitee.apanlh.util.reflection;

import com.gitee.apanlh.exp.UnknownTypeException;
import com.gitee.apanlh.util.base.ChooseOr;
import com.gitee.apanlh.util.base.CollUtils;
import com.gitee.apanlh.util.base.Empty;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.IteratorUtils;
import com.gitee.apanlh.util.base.MapUtils;
import com.gitee.apanlh.util.base.StringUtils;
import com.gitee.apanlh.util.valid.ValidParam;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 * 	类转换方法
 * 	
 * 	@author Pan
 */
public class ClassConvertUtils {
	
	private static final List<String> BOOLEAN_LIST = CollUtils.newArrayList("1", "yes", "YES", "true", "TRUE", "ok" , "on", "y" , "Y", "OK", "ON");
			
	/**
	 * 	构造函数
	 * 
	 * 	@author Pan
	 */
	private ClassConvertUtils() {
		//	不允许外部实例
		super();
	}
	
	/**
	 * 	JavaBean转换成HashMap
	 * 	<br>忽略静态字段
	 * 	
	 * 	@author Pan
	 *  @param  <T>     数据类型
	 * 	@param  bean	对象
	 * 	@return	Map
	 */
	public static <T> Map<String, Object> toMap(T bean) {
		return toMap(bean, true);
	}
	
	/**
	 * 	JavaBean 转换成HashMap
	 * 	<br>自定义忽略静态字段
	 * 	
	 * 	@author Pan
	 *  @param  <T>      数据类型
	 * 	@param  bean	对象
	 * 	@param  ignoreStaticField	true忽略静态字段
	 * 	@return Map
	 */
	public static <T> Map<String, Object> toMap(T bean, boolean ignoreStaticField) {
		Field[] fields = ReflectionUtils.getFields(bean, ignoreStaticField);
		return MapUtils.newHashMap(newMap -> IteratorUtils.array(fields, field -> newMap.put(field.getName(), ReflectionUtils.getFieldValue(field, bean))), fields.length);
	}

	/**	
	 * 	用于javaBean转换Map类型为 {@code Map<String, String>}
	 * 	
	 * 	@author Pan
	 *  @param  <T>      数据类型
	 * 	@param  bean	对象
	 * 	@return	Map
	 */
	public static <T> Map<String, String> toMapString(T bean) {
		Field[] fields = ReflectionUtils.getFields(bean, true);
		return MapUtils.newHashMap(map -> IteratorUtils.array(fields, field -> map.put(field.getName(), String.valueOf(ReflectionUtils.getFieldValue(field, bean)))), fields.length);
	}
	
	/**
	 * 	JavaBean转换成LinkedHashMap
	 * 	<br>忽略静态字段
	 * 	
	 * 	@author Pan
	 *  @param  <T>      数据类型
	 * 	@param  bean	对象
	 * 	@return	Map
	 */
	public static <T> Map<String, Object> toLinkedHashMap(T bean) {
		return toLinkedHashMap(bean, true);
	}
	
	/**
	 * 	JavaBean 转换成LinkedHashMap
	 * 	<br>自定义忽略静态字段
	 * 	
	 * 	@author Pan
	 *  @param  <T>      数据类型
	 * 	@param  bean	对象
	 * 	@param  ignoreStaticField	true忽略静态字段
	 * 	@return	Map
	 */
	public static <T> Map<String, Object> toLinkedHashMap(T bean, boolean ignoreStaticField) {
		Field[] fields = ReflectionUtils.getFields(bean, ignoreStaticField);
		return MapUtils.newLinkedHashMap(newMap -> IteratorUtils.array(fields, field -> newMap.put(field.getName(), ReflectionUtils.getFieldValue(field, bean))));
	}
	
	/**
	 * 	Map转换相对应的Bean
	 * 	
	 * 	@author Pan
	 *  @param  <T>         数据类型
	 *  @param  <V>     	值类型
	 * 	@param 	params		参数
	 * 	@param 	clazz		类
	 * 	@return	T
	 */
	public static <T, V> T toBean(Map<String, V> params, Class<T> clazz) {
		return MapUtils.isEmpty(params) ? null : ReflectionUtils.setFields(clazz, params);
	}
	
	/**	
	 * 	map转换成bean并且验证值全部存在才可转换
	 * 	<br>否则抛出异常
	 * 	
	 * 	@author Pan
	 *  @param  <T>         数据类型
	 *  @param  <V>     	值类型
	 * 	@param  paramMap			参数Map
	 * 	@param  clazz targetClass 	转换的类
	 * 	@return	T
	 */
	public static <T, V> T toBeanRequired(Map<String, V> paramMap, Class<T> clazz) {
		T t = toBean(paramMap, clazz);
		if (!ValidParam.requiredBean(t)) {
			throw new IllegalArgumentException("map转换bean失败! 转换bean时某一个值为空或属性名与map值匹配不上!");
		}
		return t;
	}
	
	/**	
	 * 	int转换基础类型long
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	long
	 */
	public static long toLong(String value) {
		return Long.parseLong(value);
	}
	
	/**	
	 * 	int转换基础类型long
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@param 	radix	进制
	 * 	@return	long
	 */
	public static long toLong(String value, int radix) {
		return Long.valueOf(value, radix);
	}
	
	/**	
	 * 	int转换基础类型long
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	long
	 */
	public static long toLong(int value) {
		return value;
	}
	
	/**	
	 * 	Integer转换基础类型long
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	long
	 */
	public static long toLong(Integer value) {
		return value.longValue();
	}
	
	/**	
	 * 	int转换包装类型Long
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	Long
	 */
	public static Long toWrapperLong(int value) {
		return toLong(value);
	}
	
	/**	
	 * 	Integer转换包装类型Long
	 * 
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	Long
	 */
	public static Long toWrapperLong(Integer value) {
		return toLong(value);
	}
	
	/**	
	 * 	Integer转换包装类型Long
	 * 
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	Long
	 */
	public static Long toWrapperLong(String value) {
		return toLong(value);
	}
	
	/**		
	 * 	将char转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(char value) {
		return String.valueOf(value);
	}
	
	/**		
	 * 	将char[]转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(char[] value) {
		return new String(value);
	}
	
	/**		
	 * 	将int转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(int value) {
		return Integer.toString(value);
	}
	
	/**		
	 * 	将Integer转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(Integer value) {
		return Integer.toString(value);
	}
	
	/**		
	 * 	将long转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(long value) {
		return Long.toString(value);
	}
	
	/**		
	 * 	将Long转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(Long value) {
		return Long.toString(value);
	}
	
	/**		
	 * 	将double转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(double value) {
		return Double.toString(value);
	}
	
	/**		
	 * 	将Double转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(Double value) {
		return Double.toString(value);
	}
	
	/**		
	 * 	将float转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(float value) {
		return Float.toString(value);
	}
	
	/**		
	 * 	将Float转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(Float value) {
		return Float.toString(value);
	}
	
	/**		
	 * 	将boolean转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(boolean value) {
		return ChooseOr.create(value, StringUtils.TRUE_STR).orElse(StringUtils.FALSE_STR);
	}
	
	/**		
	 * 	将Object转换为String	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static String toStr(Object value) {
		return (value == null) ? null : value.toString();
	}
	
	/**		
	 * 	将String转换为Int	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	String
	 */
	public static int toInt(String value) {
		return toInt(value, 10);
	}
	
	/**		
	 * 	将String转换为Int	
	 * 	<br>指定进制
	 * 
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@param 	radix	进制
	 * 	@return	String
	 */
	public static int toInt(String value, int radix) {
		return Integer.parseInt(value, radix);
	}
	
	/**		
	 * 	将Long转换为int	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	int
	 */
	public static int toInt(Long value) {
		return toInt(toStr(value));
	}
	
	/**		
	 * 	将Integer转换为int	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	int
	 */
	public static int toInt(Integer value) {
		return value == null ? 0 : value;
	}
	
	/**		
	 * 	将Object转换为int	
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	int
	 */
	public static int toInt(Object value) {
		if (value instanceof Integer) {
			return toInt((Integer) value);
		}
		if (value instanceof Long) {
			return toInt((Long) value);
		}
		if (value instanceof String) {
			return toInt((String) value);
		}
		throw new UnknownTypeException("未知类型 仅支持 int/long/String类型");
	}
	
	/**	
	 * 	将值转换为boolean
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	boolean
	 */
	public static boolean toBoolean(String value) {
		return ChooseOr.create(BOOLEAN_LIST.contains(value), true)
				.orElse(false);
	}
	
	/**	
	 * 	将value值转换为boolean
	 * 	<br>0将转化为false
	 * 	<br>1将转化为true
	 *  <br>非0或1将抛出异常
	 *  
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	boolean
	 */
	public static boolean toBoolean(int value) {
		return ChooseOr.create(Eq.object(0, value), false)
				.orElseIf(Eq.object(1, value), true)
				.orElse(new IllegalArgumentException("error parameter only 0 or 1 required"));
	}
	
	/**	
	 * 	将long值转换为boolean
	 * 	<br>0将转化为false
	 * 	<br>1将转化为true
	 * 	
	 * 	@author Pan
	 * 	@param 	value	值
	 * 	@return	boolean
	 */
	public static boolean toBoolean(long value) {
		return ChooseOr.create(Eq.object(0L, value), false)
			.orElseIf(Eq.object(1L, value), true)
			.orElse(new IllegalArgumentException("error parameter only 0 or 1 required"));
	}
	
	/**	
	 * 	byte[]转换char[]
	 * 	
	 * 	@author Pan
	 * 	@param  b	字节数组
	 * 	@return	char[]
	 */
	public static char[] toChar(byte[] b) {
        if (b == null || b.length == 0) {
            return Empty.arrayChar();
        }
        
        char[] chars = new char[b.length / 2];
        for (int byteNext = 0, len = b.length, i = 0; i < len; chars[byteNext++] = (char) ((b[i++] & 255) + ((b[i++] & 255) << 8))) {
        	//	不做处理
        }
        return chars;
    }
	
	/**	
	 * 	chat[]转byte[]
	 * 	
	 * 	@author Pan
	 * 	@param  c 字符数组
	 * 	@return	byte[]
	 */
	public static byte[] toByte(char[] c) {
        if (c == null || c.length == 0) {
            return Empty.arrayByte();
        }
        
        byte[] bytes = new byte[c.length * 2];
        int i = 0;
        for(int j = 0, len = c.length; j < len; bytes[i++] = (byte)(c[j++] >> 8 & 255)) {
        	bytes[i++] = (byte)(c[j] & 255);
        }
        return bytes;
    }
	
	/**	
	 * 	自定义强转
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 * 	@param 	<R>		类型
	 * 	@param 	value	值
	 * 	@return R
	 */
	@SuppressWarnings("unchecked")
	public static <T, R> R cast(T value) {
		if (ValidParam.isNull(value)) {
			return null;
		}
		return (R) value;
	}
	
	/**	
	 * 	强转String
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 * 	@param 	value	值
	 * 	@return String
	 */
	public static <T> String castString(T value) {
		return cast(value);
	}
	
	/**
	 * 	强转List
	 * 	<br>内部捕获检查
	 * 
	 * 	@param 	<T>		值
	 * 	@param 	<R>		类型
	 * 	@param 	value	值
	 * 	@return	List
	 */
	public static <T, R> List<R> castList(T value) {
		return cast(value);
	}

	/**	
	 * 	强转Map
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 *  @param  <K>     键类型
	 *  @param  <V>     值类型
	 * 	@param 	value	值
	 * 	@return Map
	 */
	public static <T, K, V> Map<K , V> castMap(T value) {
		return cast(value);
	}

	/**
	 * 	强转Map
	 * 	<br>value为String
	 * 	<br>内部捕获检查
	 *
	 * 	@author Pan
	 * 	@param 	<T>		值
	 *  @param  <K>     键类型
	 * 	@param 	value	值
	 * 	@return Map
	 */
	public static <T, K> Map<K , String> castMapStr(T value) {
		return cast(value);
	}

	/**	
	 * 	强转byte[]
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 * 	@param 	value	值
	 * 	@return String
	 */
	public static <T> byte[] castArrayByte(T value) {
		return cast(value);
	}
	
	/**	
	 * 	强转short[]
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 * 	@param 	value	值
	 * 	@return String
	 */
	public static <T> short[] castArrayShort(T value) {
		return cast(value);
	}
	
	/**	
	 * 	强转int[]
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 * 	@param 	value	值
	 * 	@return String
	 */
	public static <T> int[] castArrayInteger(T value) {
		return cast(value);
	}
	
	/**	
	 * 	强转long[]
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 * 	@param 	value	值
	 * 	@return String
	 */
	public static <T> long[] castArrayLong(T value) {
		return cast(value);
	}
	
	/**	
	 * 	强转float[]
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 * 	@param 	value	值
	 * 	@return String
	 */
	public static <T> float[] castArrayFloat(T value) {
		return cast(value);
	}
	
	/**	
	 * 	强转double[]
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 * 	@param 	value	值
	 * 	@return String
	 */
	public static <T> double[] castArrayDouble(T value) {
		return cast(value);
	}
	
	/**	
	 * 	强转boolean[]
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 * 	@param 	value	值
	 * 	@return String
	 */
	public static <T> boolean[] castArrayBoolean(T value) {
		return cast(value);
	}
	
	/**	
	 * 	强转char[]
	 * 	<br>内部捕获检查
	 * 	
	 * 	@author Pan
	 * 	@param 	<T>		值
	 * 	@param 	value	值
	 * 	@return String
	 */
	public static <T> char[] castArrayChar(T value) {
		return cast(value);
	}
}
